package org.jeecg.modules.sggg.controller;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.util.DySmsEnum;
import org.jeecg.common.util.DySmsHelper;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.config.StaticConfig;
import org.jeecg.modules.sggg.entity.*;
import org.jeecg.modules.sggg.service.ISgGlucoseRecordService;
import org.jeecg.modules.sggg.service.ISgMemberService;
import org.jeecg.modules.wechatSendMessage.TemplateData;
import org.jeecg.modules.wechatSendMessage.WxMssVo;
import org.jeecg.modules.wechatSendMessage.subscribeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigInteger;
import java.net.InetAddress;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Api(tags = "血糖、血压测量数据管理")
@RestController
@RequestMapping("/measure")
@Slf4j
public class SgMeasureController extends JeecgController<SgGlucoseRecord, ISgGlucoseRecordService> {

    @Autowired
    private ISgGlucoseRecordService sgGlucoseRecordService;

    @Autowired
    private SgDeviceRelevanceController sgDeviceRelevanceController;

    @Autowired
    private SgBlutdruckRecordController sgBlutdruckRecordController;

    @Autowired
    private SgGlucoseRecordController sgGlucoseRecordController;

    @Autowired
    private ISgMemberService sgMemberService;

    @Autowired
    private SgOperationRecordsController sgOperationRecordsController;

    /**
     * 通过爱奥乐网络设备获取测量数据
     *
     * @param data
     * @return
     * @throws Exception
     */
    @ApiOperation(value = "获取血糖测量数据", notes = "获取血糖测量数据")
    @GetMapping(value = "/bloodSugar")
    public Result<String> receiveDataForBioland(String data) throws Exception {
        // 解析测量数据指令  01：血压/02：血糖
        if (data.substring(9, 11).equals("01")) {
            log.info("爱奥乐血压计测量数据==========" + data);
            SgBlutdruckRecord sgBlutdruckRecord = new SgBlutdruckRecord();
            sgBlutdruckRecord.setDeviceId(data.substring(11, 20)); // 血压计设备唯一编码
            // 是否有居民绑定该设备
            SgDeviceRelevance sgDeviceRelevance = sgDeviceRelevanceController.querySerialNumber(sgBlutdruckRecord.getDeviceId()).getResult();
            if (sgDeviceRelevance != null) {
                SgMember m = sgMemberService.getById(sgDeviceRelevance.getMemberId());
                sgBlutdruckRecord.setMemberId(sgDeviceRelevance.getMemberId()); // 测量人id
                sgBlutdruckRecord.setSysOrgCode(m.getSysOrgCode()); // 测量人所属机构
                sgBlutdruckRecord.setSbpval(Double.valueOf(data.substring(20, 23))); // 收缩压
                sgBlutdruckRecord.setDbpval(Double.valueOf(data.substring(23, 26))); // 舒张压
                sgBlutdruckRecord.setHeartRate(Integer.valueOf(data.substring(26, 29))); // 心率
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmm");
                Date date = dateFormat.parse(data.substring(29, 39));
                sgBlutdruckRecord.setMeasuringTime(date); // 测量时间
                sgBlutdruckRecordController.add(sgBlutdruckRecord);
            }
        } else if (data.substring(9, 11).equals("02")) {
            log.info("爱奥乐血糖仪测量数据==========" + data);
            SgGlucoseRecord sgGlucoseRecord = new SgGlucoseRecord();
            sgGlucoseRecord.setDeviceId(data.substring(11, 20)); // 血糖仪设备唯一编码
            // 是否有居民绑定该设备
            SgDeviceRelevance sgDeviceRelevance = sgDeviceRelevanceController.querySerialNumber(sgGlucoseRecord.getDeviceId()).getResult();
            if (sgDeviceRelevance != null) {
                SgMember m = sgMemberService.getById(sgDeviceRelevance.getMemberId());
                sgGlucoseRecord.setMemberId(sgDeviceRelevance.getMemberId()); // 测量人id
                sgGlucoseRecord.setSysOrgCode(m.getSysOrgCode()); // 测量人所属机构
                // 数值部分以mg/dL为单位传送，如果要显示为mmol/dL的单位，则要除以18，并四舍五入才能与血糖仪端显示的数据一致。
                DecimalFormat df = new DecimalFormat("#.0");
                sgGlucoseRecord.setGluval(Double.parseDouble(df.format(Double.valueOf(data.substring(26, 29)) / 18))); // 血糖测量数值
                //SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmm");
                //Date date = dateFormat.parse(data.substring(29, 39).toString());
                sgGlucoseRecord.setMeasuringTime(DateTime.now()); // 测量时间  update-begin-Author:Garand--Date:23-05-10--for: 调整为不从设备上获取时间
                sgGlucoseRecord.setPhase(getPhase(sgGlucoseRecord.getMeasuringTime())); // 测量时机
                // 血糖等级
                switch (data.substring(25, 26)) {
                    case "0": // 无选择
                        sgGlucoseRecordController.add(sgGlucoseRecord);
                        return Result.OK(serviceData());
                    case "1": // 餐前
                        if (sgGlucoseRecord.getGluval() >= 3.9 && sgGlucoseRecord.getGluval() <= 6.1) {
                            sgGlucoseRecord.setLevel(0);
                        } else if (sgGlucoseRecord.getGluval() < 3.9) {
                            sgGlucoseRecord.setLevel(1);
                        } else if (sgGlucoseRecord.getGluval() > 6.1) {
                            sgGlucoseRecord.setLevel(2);
                        }
                        break;
                    case "2": // 餐后
                        if (sgGlucoseRecord.getGluval() <= 7.8) {
                            sgGlucoseRecord.setLevel(0);
                        } else if (sgGlucoseRecord.getGluval() >= 11.1) {
                            sgGlucoseRecord.setLevel(2);
                        } else if (sgGlucoseRecord.getGluval() < 2.8) {
                            sgGlucoseRecord.setLevel(1);
                        }
                        break;
                }
                // 是否干预
                if (m.getSugarMax() != null && m.getSugarMin() != null) {
                    sgGlucoseRecord.setIntervene(sgGlucoseRecord.getGluval() >= m.getSugarMax() || sgGlucoseRecord.getGluval() <= m.getSugarMin() ? 0 : 1);
                } else {
                    sgGlucoseRecord.setIntervene(1);
                }
                sgGlucoseRecordService.save(sgGlucoseRecord);
                // 发送短信和微信订阅消息
                if (sgGlucoseRecord.getIntervene() == 0) {
                    sgGlucoseRecordController.sendSms(m, sgGlucoseRecord);
                }
                // 健康任务
                sgOperationRecordsController.dailyMeasurementTask("医防融合设备使用", 1, m.getId());
            }
        }
        return Result.OK(serviceData());
    }

    /**
     * 通过脉搏波血压计获取测量数据
     *
     * @param data
     * @return
     */
    @PostMapping("/receiveDataForMaibobo")
    public JSONObject receiveDataForMaibobo(@RequestBody Maibobo data) throws Exception {
        log.info("脉搏波血压计测量数据==========" + data);
        SgBlutdruckRecord sgBlutdruckRecord = new SgBlutdruckRecord();
        SgDeviceRelevance sgDeviceRelevance = sgDeviceRelevanceController.querySerialNumber(data.getDeviceSim()).getResult();
        if (sgDeviceRelevance != null) {
            SgMember m = sgMemberService.getById(sgDeviceRelevance.getMemberId());
            sgBlutdruckRecord.setMemberId(sgDeviceRelevance.getMemberId()); // 测量人id
            sgBlutdruckRecord.setSysOrgCode(m.getSysOrgCode()); // 测量人所属机构
            sgBlutdruckRecord.setDeviceId(data.getDeviceSim()); // 血压计设备唯一编码
            sgBlutdruckRecord.setSbpval(Double.parseDouble(data.getHighPressure())); // 收缩压
            sgBlutdruckRecord.setDbpval(Double.parseDouble(data.getLowVoltage())); // 舒张压
            sgBlutdruckRecord.setHeartRate(Integer.parseInt(data.getPulse())); // 心率
            //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //Date date = dateFormat.parse(data.getUploadTime());
            sgBlutdruckRecord.setMeasuringTime(DateTime.now()); // 测量时间 update-begin-Author:Garand--Date:23-05-10--for: 调整为不从设备上获取时间
            sgBlutdruckRecordController.add(sgBlutdruckRecord);
            JSONObject obj = new JSONObject();
            obj.put("code", 1);
            obj.put("status", "success");
            obj.put("msg", "成功");
            return obj;
        } else {
            JSONObject obj = new JSONObject();
            obj.put("code", 2);
            obj.put("status", "error");
            obj.put("msg", "该设备没有绑定居民");
            return obj;
        }
    }

    //#region 数据解析相关方法

    /**
     * 生成服务平台返回的31字节数据
     *
     * @return
     * @throws Exception
     */
    public String serviceData() throws Exception {
        /*
        服务平台返回数据示例：
        服务器 IP: 42.121.236.135 (0x2A:0x79:0xEC:0x87).
        服务器端口：8014 （0x1F4E）
        服务器时间：14年7月8日10时39分
        服务平台返回31字节数据：+IP2A79EC874E1F690E07080A272COK
        */
        String serviceData = "+IP";
        InetAddress ipAddress = InetAddress.getLocalHost();
        byte[] ipAddressBytes = ipAddress.getAddress();
        String hexIpAddress = new BigInteger(1, ipAddressBytes).toString(16);
        serviceData += hexIpAddress;
        serviceData += Integer.toHexString(8693);
        serviceData += IPPort();
        serviceData += timeXOR();
        serviceData += "OK";
        return serviceData.toUpperCase();
    }

    /**
     * 获取ip地址和端口，按字节HEX异或
     *
     * @return
     * @throws Exception
     */
    public String IPPort() throws Exception {
        // 获取本机IP地址和端口号
        InetAddress ip = InetAddress.getLocalHost();
        int port = 8693;

        // 将IP地址和端口号组合成一个字节数组
        byte[] bytes = new byte[5];
        byte[] ipBytes = ip.getAddress();
        for (int i = 0; i < 4; i++) {
            bytes[i] = ipBytes[i];
        }
        bytes[4] = (byte) (port >> 8);
        bytes[3] = (byte) port;

        // 对每个字节进行HEX异或操作
        byte xorResult = bytes[0];
        for (int i = 1; i < bytes.length; i++) {
            xorResult ^= bytes[i];
        }
        return Integer.toHexString(xorResult & 0xff);
    }

    /**
     * 获取时间，按字节HEX异或
     *
     * @return
     */
    public String timeXOR() {
        // 获取当前的年月日时分
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonthValue();
        int day = now.getDayOfMonth();
        int hour = now.getHour();
        int minute = now.getMinute();

        // 将年月日时分组合成一个字节数组
        byte[] bytes = new byte[6];
        bytes[0] = (byte) (year >> 8);
        bytes[1] = (byte) year;
        bytes[2] = (byte) month;
        bytes[3] = (byte) day;
        bytes[4] = (byte) hour;
        bytes[5] = (byte) minute;

        // 对每个字节进行HEX异或操作
        byte xorResult = bytes[0];
        for (int i = 1; i < bytes.length; i++) {
            xorResult ^= bytes[i];
        }
        return Integer.toHexString(xorResult & 0xff);
    }

    /**
     * 根据时间获取测量时机
     *
     * @param measuringTime
     * @return
     */
    public Integer getPhase(Date measuringTime) {
        Instant instant = measuringTime.toInstant();
        ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
        LocalDateTime specifiedTime = zonedDateTime.toLocalDateTime();
        LocalTime time = specifiedTime.toLocalTime();

        LocalTime earlyMorning = LocalTime.parse("00:00");
        LocalTime emptyStomach = LocalTime.parse("06:00");
        LocalTime breakfast = LocalTime.parse("08:00");
        LocalTime beforeLunch = LocalTime.parse("11:00");
        LocalTime afterLunch = LocalTime.parse("13:00");
        LocalTime dinner = LocalTime.parse("18:00");
        LocalTime beforeBed = LocalTime.parse("23:00");

        if (time.isAfter(earlyMorning) && time.isBefore(emptyStomach)) {
            return 0;
        } else if (time.isAfter(emptyStomach) && time.isBefore(breakfast)) {
            return 1;
        } else if (time.isAfter(breakfast) && time.isBefore(beforeLunch)) {
            return 2;
        } else if (time.isAfter(beforeLunch) && time.isBefore(afterLunch)) {
            return 3;
        } else if (time.isAfter(afterLunch) && time.isBefore(dinner)) {
            return 4;
        } else if (time.isAfter(dinner) && time.isBefore(beforeBed)) {
            return 5;
        } else if (time.isAfter(beforeBed) || time.equals(beforeBed)) {
            return 6;
        }
        return 1;
    }

    //#endregion

}
